package org.toools.rss2social;

/**
 * reads an rss feed xml from the specified url and posts new entries to delicious and twitter
 *
 * @author stefan asseg
 */
import com.sun.syndication.feed.synd.SyndCategoryImpl;
import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;
import del.icio.us.Delicious;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import twitter4j.Twitter;
import twitter4j.TwitterException;

public class Main {

    private static final Log log = LogFactory.getLog(Main.class);
    private static final String configFile = "toools-rss2social_config.properties";
    private static final String saveFile = "toools-rss2social_save.properties";
    private static Properties properties = new Properties();
    private static String feed;
    private static String delicious_user;
    private static String delicious_pass;
    private static String twitter_user;
    private static String twitter_pass;
    private static boolean delicious_activate;
    private static boolean twitter_activate;
    private static boolean delicious_post_images;
    private static String delicious_image_title;
    private static Vector<String> delicious_masked_titles = new Vector<String>();
    private static Delicious delicious;
    private static Twitter twitter;
    private static Long lastfeedDateLastSession;
    private static Long lastfeedDateThisSession = 0L;

    public static void main(String args[]) {
        try {
            readConfig();
            if (!delicious_activate && !twitter_activate) {
                return;
            }

            initApis();

            URL feedUrl = new URL(feed);
            SyndFeedInput input = new SyndFeedInput();
            SyndFeed sf = input.build(new XmlReader(feedUrl));
            List<SyndEntry> entries = sf.getEntries();
            Collections.reverse(entries);

            for (SyndEntry entry : entries) {
                long thisFeedsDate = entry.getPublishedDate().getTime();

                if (thisFeedsDate > lastfeedDateLastSession) {
                    if (delicious_activate) {
                        rssItem2Delicious(entry);
                    }
                    if (twitter_activate) {
                        try {
                            rssItem2Twitter(entry);
                        } catch (TwitterException e) {
                            log.error("Could not post entry [" + entry.getTitle() + "] to twitter.");
                        }
                    }
                } else {
                    log.info("skipped entry [" + entry.getTitle() + "]");
                }

                if (thisFeedsDate > lastfeedDateThisSession) {
                    lastfeedDateThisSession = thisFeedsDate;
                    log.debug("this feed is newer than the newest feed processed so far in this run, time = [" + thisFeedsDate + "]");
                }
            }

            if (lastfeedDateThisSession > lastfeedDateLastSession) {
                properties.setProperty(feed, lastfeedDateThisSession.toString());
                properties.store(new FileOutputStream(saveFile), "org.toools.rss.RSS2Web: date of newest feed processed for every feed processed so far");
                log.debug("the newest feed processed in this run is newer than the newest feed processed in the last session, time = [" + lastfeedDateThisSession + "]");
            }
        } catch (FileNotFoundException e) {
            log.error("Error reading config file [" + configFile + "].");
        } catch (IOException e) {
            log.error("An IOException occured.");
        } catch (FeedException e) {
            log.error("Error reading RSS-feed.");
        }
    }

    private static void readConfig() throws FileNotFoundException, IOException {
        properties.load(new FileInputStream(configFile));
        feed = properties.getProperty("feed");
        delicious_user = properties.getProperty("delicious_user");
        delicious_pass = properties.getProperty("delicious_pass");
        twitter_user = properties.getProperty("twitter_user");
        twitter_pass = properties.getProperty("twitter_pass");
        final String da = properties.getProperty("delicious_activate");
        delicious_activate = da != null && (da.equals("1") || da.equals("true"));
        final String ta = properties.getProperty("twitter_activate");
        twitter_activate = ta != null && (ta.equals("1") || ta.equals("true"));
        final String dpi = properties.getProperty("delicious_post_images");
        delicious_post_images = dpi != null && (dpi.equals("1") || dpi.equals("true"));
        delicious_image_title = properties.getProperty("delicious_image_title", "");
        final String dtf = properties.getProperty("delicious_masked_titles", "");
        for (String s : dtf.split(",")) {
            delicious_masked_titles.add(s.trim().toLowerCase());
        }
        properties.clear();

        new File(saveFile).createNewFile();
        properties.load(new FileInputStream(saveFile));
        lastfeedDateLastSession = Long.valueOf(properties.getProperty(feed, "0"));
        properties.clear();
        log.debug("lastfeedDateLastSession = " + lastfeedDateLastSession);
    }

    private static void initApis() {
        if (delicious_activate) {
            delicious = new Delicious(delicious_user, delicious_pass);
        }
        if (twitter_activate) {
            twitter = new Twitter(twitter_user, twitter_pass);
        }
    }

    private static void rssItem2Delicious(SyndEntry entry) {
        final String link = entry.getLink();
        final String title = entry.getTitle();
        final SyndContent descCont = entry.getDescription();
        final String description = descCont != null ? descCont.getValue() : "";

        String tags = "";
        for (Object category : entry.getCategories()) {
            tags += ((SyndCategoryImpl) category).getName() + " ";
        }
        final Date date = entry.getPublishedDate();

        // post this post's link to delicious
        postLinkToDelicious("link to original post", link, title, description, tags, date);

        // post all links that occur in the content to delicious with the post's tags
        final String content = entry.getContents().get(0).toString();
        for (Entry<String, String> e : extractLinks(content).entrySet()) {
            postLinkToDelicious("link from content", e.getKey(), e.getValue(), "", tags, date);
        }
    }

    private static void postLinkToDelicious(String mode, String link, String title, String description, String tags, Date date) {
        final boolean success = delicious.addPost(link, title, description, tags, date);
        log.info("posting " + mode + " to delicious: url = [" + link + "], title = [" + title + "] ... [" + (success ? "success" : "failed") + "]");
    }

    private static void rssItem2Twitter(SyndEntry entry) throws TwitterException {
        twitter.update(entry.getTitle() + " [" + entry.getLink() + "]");
        log.info("posting to twitter: resulting status = [" + entry.getTitle() + " [" + entry.getLink() + "]]");
    }

    private static HashMap<String, String> extractLinks(String string) {
        HashMap<String, String> links = new HashMap<String, String>();

        // extract links with titles from string
        final String linkPrefix = "<a href=\"";
        final char linkSuffix = '"';
        final char titlePrefix = '>';
        final char titleSuffix = '<';
        int linkStart;
        while ((linkStart = string.indexOf(linkPrefix)) != -1) {
            string = string.substring(linkStart + linkPrefix.length());

            int linkEnd = string.indexOf(linkSuffix);
            String link = string.substring(0, linkEnd);
            String title = string.substring(string.indexOf(titlePrefix) + 1, string.indexOf(titleSuffix));
            if (title.length() > 0 || delicious_post_images) {
                if (title.length() == 0) {
                    title = delicious_image_title;
                }

                if (delicious_masked_titles.contains(title.toLowerCase())) {
                    title = extractHostnameFromLink(link);
                }

                links.put(link, title);
            }

            string = string.substring(linkEnd);
        }

        // remove duplicates
        HashMap<String, String> uniqueLinks = new HashMap<String, String>();
        for (Entry<String, String> e : links.entrySet()) {
            if (!uniqueLinks.containsKey(e.getKey())) {
                uniqueLinks.put(e.getKey(), e.getValue());
            }
        }

        return uniqueLinks;
    }

    private static String extractHostnameFromLink(String link) {
        final String hostname = link.replaceFirst("http://", "");
        return hostname.substring(0, hostname.indexOf('/'));
    }
}